package com.yyfax.pay.third.facade.allinpay;

import java.net.SocketTimeoutException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.WebUtils;

import com.yyfax.commons.http.HttpUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.common.Pair;
import com.yyfax.pay.common.enums.AllInPayRspCodeEnum;
import com.yyfax.pay.common.enums.PayModeEnum;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.enums.PayTypeEnum;
import com.yyfax.pay.common.enums.PaymentEnum;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.util.AllInPayUtil;
import com.yyfax.pay.common.util.XmlUtil;
import com.yyfax.pay.config.data.service.MerchantPaymentService;
import com.yyfax.pay.third.model.to.allinpay.AllInPayConfigExt;
import com.yyfax.pay.third.model.to.allinpay.AllInPayReqXML;
import com.yyfax.pay.third.model.to.allinpay.AllInPayRspBody;
import com.yyfax.pay.third.model.to.allinpay.AllInPayRspXML;
import com.yyfax.pay.third.model.to.allinpay.AllInPayRspXML.Info;
import com.yyfax.pay.third.model.to.allinpay.PayoutRefundReq;
import com.yyfax.pay.third.model.to.allinpay.PayoutReqTransXML;
import com.yyfax.pay.third.model.to.allinpay.PayoutRspTransXML;
import com.yyfax.pay.third.model.to.allinpay.QueryReqXML;
import com.yyfax.pay.third.model.to.allinpay.QueryRspXML;
import com.yyfax.pay.third.model.to.yyfax.PayoutDataBinder;
import com.yyfax.pay.third.model.to.yyfax.PayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayoutRefundDataBinder;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYParams;
import com.yyfax.pay.third.service.ThirdPayService;

/**
 * 通联支付服务
 *
 * @author buyi
 * @date 2018-05-10 11:17:08
 * @since v2.1.5
 */
public class AllInPayFacade extends ThirdPayService {
	private static final Logger logger = LoggerFactory.getLogger(AllInPayFacade.class);

	/** 默认请求协议 */
	private static final String DEFAULT_CONTENT_TYPE = "application/tlt-notify";

	private static final String DEFAULT_CHARSET = "GBK";

	/** 代付查询：交易状态条件--全部 */
	private static final String QUERY_REQ_STATUS_ALL = "2";
	/** 代付查询：查询类型--按提交日期 */
	private static final String QUERY_REQ_TYPE_COMMIT_DATE = "1";
	/** 代付查询请求流水前缀 */
	private static final String QUERY_REQ_SN_PRE = "QRSN";

	@Resource
	private MerchantPaymentService merchantPaymentService;

	public AllInPayFacade() {
		this.facadeName = "通联";
	}

	/**
	 * 获取支付凭证
	 *
	 * @author buyi
	 * @date 2018-05-10 11:17:08
	 * @since v2.1.5
	 * @param merchantCode
	 * @param payTypeEnum
	 * @return
	 */
	public AllInPayConfigExt getConfigExt(String merchantCode, PayTypeEnum payTypeEnum) {
		final String op = "AllInPayFacade.getConfigExt";
		AllInPayConfigExt configExt = null;
		try {
			configExt = merchantPaymentService.queryByThirdMerchantCodeForExt(merchantCode, PaymentEnum.ALL_IN_PAY.getValue(), payTypeEnum.getValue(),
					PayModeEnum.AUTH_PAY.getValue(), AllInPayConfigExt.class);
		} catch (Exception e) {
			logger.error(Log.op(op).msg("获取文件服务配置信息异常").kv("merchantCode", merchantCode).kv("payType", payTypeEnum.getValue()).toString(), e);
			throw PayExceptionCode.ERROR_MERCHANT_CONFIG_ILLEGAL.exp();

		}

		if (configExt == null) {
			logger.error(Log.op(op).msg("获取文件服务配置信息为空").kv("merchantCode", merchantCode).kv("payType", payTypeEnum.getValue()).toString());
			throw PayExceptionCode.ERROR_MERCHANT_CONFIG_ILLEGAL.exp();
		}

		return configExt;
	}

	/**
	 * 通联代付
	 *
	 * @author buyi
	 * @date 2018-05-10 11:17:08
	 * @since v2.1.5
	 * @param req
	 * @return
	 * @throws Exception
	 */
	@Override
	public void payoutOrderNew(PayoutOrderYYParams req, PayoutDataBinder binder) throws Exception {
		final String op = "AllInPayFacade.payoutOrder";
		// step1.转换参数为通联代付请求参数
		AllInPayConfigExt configExt = getConfigExt(req.getMerchantCode(), PayTypeEnum.PAY_OUT);

		// 业务代码，默认走代付-“09900”
		String submitTime = DateUtil.date2Str(DateUtil.str2DateTime(req.getPayOrderTime()), DateUtil.FORMAT_YYYYMMDDHHMMSS);

		PayoutReqTransXML transXML = PayoutReqTransXML.newInstance().businessCode("09900").merchantId(configExt.getMerchantId())
				.submitTime(submitTime).userCode(req.getUserId()).accountNo(req.getPayeeCardNo()).accountName(req.getPayeeName()).accountProp("0")
				.amount(String.valueOf(req.getAmount()));

		AllInPayReqXML allInPayReqXML = AllInPayReqXML.Info.newInstance().trxCode(configExt.getTrxCode()).version(configExt.getVersion())
				.dataType(configExt.getDataType()).level(configExt.getLevel()).userName(configExt.getUserName()).userPass(configExt.getPassword())
				.reqSn(req.getPayoutOrderId()).signedMsg("").build().addBody(transXML);

		// 增加签名
		String xml = AllInPayUtil.sign(req.getMerchantCode(), allInPayReqXML, configExt.getPrivateKeyPath(), configExt.getPassword());

		binder.setReqContent(xml);
		binder.setReqUrl(configExt.getUrl());
		binder.setReqDate(new Date());

		// step2.发送请求到通联
		logger.info(Log.op(op).msg("通联 | 单笔代付 | 请求报文").kv("payoutOrderId", req.getPayoutOrderId()).kv("url", configExt.getUrl()).kv("请求报文", xml)
				.toString());

		String responseStr = HttpUtil.postFormDirect(configExt.getUrl(), xml, null, DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET, null, null,
				configExt.getConnectTimeout(), configExt.getReadTimeout(), true);

		binder.setRspContent(responseStr);

		logger.info(Log.op(op).msg("通联 | 单笔代付 | 请求响应").kv("payoutOrderId", req.getPayoutOrderId()).kv("响应报文", responseStr).toString());

		if (StringUtils.isBlank(responseStr)) {
			// 如果请求响应参数为空则未知
			logger.error(Log.op(op).msg("通联 | 单笔代付 | 请求响应报文为空，需要人工介入").kv("payoutOrderId", req.getPayoutOrderId()).toString());

			// 报文为空为未知状态，返回未知状态
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}

		// step3.解析通联返回参数
		boolean sign = AllInPayUtil.verfiySign(req.getMerchantCode(), responseStr, configExt.getPublicKeyPath());
		if (!sign) {
			// 响应报文验签不通过
			logger.error(Log.op(op).msg("通联 | 单笔代付 | 请求响应报文验签不通过，订单更新成失败，需要人工介入").kv("payoutOrderId", req.getPayoutOrderId()).kv("响应报文", responseStr)
					.toString());

			// 第三方公司验签不通过，返回未知状态
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}

		// step4.转换通联返回参数为支付返回参数
		AllInPayRspXML fromXMLForXStream = XmlUtil.fromXMLForXStream(responseStr, AllInPayRspXML.class, PayoutRspTransXML.class);
		Pair<Integer, String> pairRspCode = transformRspCode(fromXMLForXStream, req.getPayoutOrderId());

		binder.setResult(pairRspCode.first(), pairRspCode.second());

	}

	/**
	 * 转换通联响应码
	 *
	 * @author buyi
	 * @date 2018-01-04 16:09:02
	 * @since v2.1.5
	 * @param rspXML
	 * @return
	 */
	private Pair<Integer, String> transformRspCode(AllInPayRspXML rspXML, String payoutOrderId) {
		final String op = "AllInPayFacade.transformRspCode";
		if (rspXML == null || rspXML.getInfo() == null) {
			logger.error(Log.op(op).msg("转换通联响应码，响应参数实体为空，响应业务状态码为未知状态，需要人工介入").kv("AllInPayRspXML", rspXML).toString());
			return Pair.of(PayExceptionCode.WARN_UNKNOWN.getCode(), "未知状态，响应信息为空");
		}

		Info info = rspXML.getInfo();

		// String reqSn = info.getReqSn();

		String infoRetCode = info.getReqCode();
		String infoErrMsg = info.getErrMsg();
		String errMsg = infoErrMsg;
		if (AllInPayRspCodeEnum.isDealing(infoRetCode)) {
			// 如果info响应码为空处理中
			return Pair.of(PayExceptionCode.DEALING.getCode(), StringUtils.isBlank(infoErrMsg) ? PayExceptionCode.DEALING.getDesc() : infoErrMsg);
		}

		// if (AllInPayRspCodeEnum.isAccept(infoRetCode)) {
		// // 如果响应码为跨行，则返回受理状态。该状态存在可能退片的场景
		// return Pair.of(PayExceptionCode.TO_CONFIRM.getCode(),
		// StringUtils.isBlank(infoErrMsg) ? PayExceptionCode.TO_CONFIRM.getDesc() : infoErrMsg);
		// }

		// 判断100014-批次号或序列号冲突，订单重复
		if (AllInPayRspCodeEnum.isDuplicate(infoRetCode)) {
			return Pair.of(PayExceptionCode.ERROR_ORDER_DUPLICATE.getCode(),
					StringUtils.isBlank(infoErrMsg) ? PayExceptionCode.ERROR_ORDER_DUPLICATE.getDesc() : infoErrMsg);
		}

		if (AllInPayRspCodeEnum.isSuccess(infoRetCode)) {
			// 如果info响应为成功，则继续判断transf的响应码

			// AllInPayRspTransXML transret = rspXML.getTransret();
			List<Object> bodys = rspXML.getBody();
			if (CollectionUtils.isEmpty(bodys)) {
				// 如果响应报文体为空，则预警
				logger.error(Log.op(op).msg("转换通联响应码，响应参数实体为空，响应业务状态码为未知状态，需要人工介入").kv("payoutOrderId", payoutOrderId).toString());
				return Pair.of(PayExceptionCode.WARN_UNKNOWN.getCode(), "未知状态，响应信息为空");
			}

			AllInPayRspBody body = (AllInPayRspBody) bodys.get(0);
			if (body == null) {
				logger.error(Log.op(op).msg("转换通联响应码，响应参数实体为空，响应业务状态码为未知状态，需要人工介入").kv("payoutOrderId", payoutOrderId).toString());
				return Pair.of(PayExceptionCode.WARN_UNKNOWN.getCode(), "未知状态，响应信息为空");
			}

			// 设置业务流水
			body.setBusiId(payoutOrderId);

			String transretRetCode = body.getRetCode();
			String transretErrMsg = body.getErrMsg();
			errMsg = transretErrMsg;
			if (AllInPayRspCodeEnum.isSuccess(transretRetCode)) {
				// 原响应码RspCodeEnum.SUCCESS没有描述，使用PayExceptionCode.SUCCESS
				return Pair.of(PayExceptionCode.SUCCESS.getCode(), PayExceptionCode.SUCCESS.getDesc());
			}

			// if (AllInPayRspCodeEnum.isAccept(transretRetCode)) {
			// // 如果响应码为跨行，则返回受理状态。该状态存在可能退片的场景
			// return Pair.of(PayExceptionCode.TO_CONFIRM.getCode(),
			// StringUtils.isBlank(transretErrMsg) ? PayExceptionCode.TO_CONFIRM.getDesc() : transretErrMsg);
			// }
		}

		// 如果info响应码不为成功，则默认为失败,或者trans响应码不为成功， 则默认为失败
		return Pair.of(PayRspCodeEnum.PAY_CODE_PAYOUT_FAIL.getValue(),
				StringUtils.isBlank(errMsg) ? PayRspCodeEnum.PAY_CODE_PAYOUT_FAIL.getDisplay() : errMsg);
	}

	/**
	 * 查询通联代付订单
	 *
	 * @author wujiande
	 * @date 2018-05-11 17:22:08
	 * @since v2.1.5
	 * @param req
	 * @return
	 * @throws Exception
	 */
	@Override
	public QueryPayoutOrderYYContent queryPayoutOrder(QueryPayoutOrderYYParams req) throws Exception {
		final String op = "AllInPayFacade.queryPayoutOrder";
		QueryPayoutOrderYYContent content = new QueryPayoutOrderYYContent();
		content.setOrderId(req.getOrderId());
		content.setUserId(req.getUserId());
		try {
			// step1.转换为查询通联代付订单的请求参数
			AllInPayConfigExt configExt = getConfigExt(req.getMerchantCode(), PayTypeEnum.PAY_OUT);
			content.setReqUrl(configExt.getUrl());
			String xml = transformQueryPayOutOrderParams(req, configExt);
			content.setReqContent(xml);

			// step2.发送请求到通联
			logger.info(Log.op(op).msg("【通联】【代付查询】请求报文").kv("payoutOrderId", req.getPayoutOrderId()).kv("url", configExt.getUrl()).kv("请求报文", xml)
					.toString());
			String responseStr = HttpUtil.postFormDirect(configExt.getUrl(), xml, null, DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET, null, null,
					configExt.getConnectTimeout(), configExt.getReadTimeout(), true);
			logger.info(Log.op(op).msg("【通联】【代付查询】请求响应").kv("payoutOrderId", req.getPayoutOrderId()).kv("响应报文", responseStr).toString());
			content.setRspContent(responseStr);

			// step3.转换为响应结果
			transformQueryPayOutOrderContent(content, req, responseStr, configExt);

		} catch (SocketTimeoutException e) {
			logger.error(Log.op(op).msg("【通联】【代付查询】请求超时").kv("payoutOrderId", req.getPayoutOrderId()).toString(), e);
			content.setResultCode(PayExceptionCode.WARN_REQ_TIME_OUT.getCode());
			content.setResultMsg(PayExceptionCode.WARN_REQ_TIME_OUT.getDesc());
		} catch (PayException e) {
			logger.error(
					Log.op(op).msg("【通联】【代付查询】业务异常").kv("merchantCode", req.getMerchantCode()).kv("payoutOrderId", req.getPayoutOrderId()).toString(),
					e);
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.error(Log.op(op).msg("【通联】【代付查询】请求未知异常").kv("payoutOrderId", req.getPayoutOrderId()).toString(), e);
			content.setResultCode(PayExceptionCode.WARN_UNKNOWN.getCode());
			content.setResultMsg("未知异常");
		}
		return content;
	}

	/**
	 * 构建查询代付的请求参数
	 *
	 * @author wujiande
	 * @date 2018-05-11 17:22:08
	 * @since v2.1.5
	 * @param req
	 * @param configExt
	 * @return
	 * @throws Exception
	 */
	private String transformQueryPayOutOrderParams(QueryPayoutOrderYYParams req, AllInPayConfigExt configExt) throws Exception {
		// step1.构建请求主体
		QueryReqXML queryReqXml = QueryReqXML.newInstance().merchantId(configExt.getMerchantId()).querySN(req.getPayoutOrderId())
				.status(QUERY_REQ_STATUS_ALL).type(QUERY_REQ_TYPE_COMMIT_DATE);
		// step2.构建请求
		AllInPayReqXML allInPayReqXML = AllInPayReqXML.Info.newInstance().trxCode(configExt.getQueryTrxCode()).version(configExt.getVersion())
				.dataType(configExt.getDataType()).level(configExt.getLevel()).userName(configExt.getUserName()).userPass(configExt.getPassword())
				.reqSn(generateQueryReqSN()).signedMsg("").build().addBody(queryReqXml);
		// step3.增加签名
		return AllInPayUtil.sign(req.getMerchantCode(), allInPayReqXML, configExt.getPrivateKeyPath(), configExt.getPassword());
	}

	/**
	 * 生成代付查询请求批次号
	 *
	 * @author wujiande
	 * @date 2018-05-18 21:37:27
	 * @since v2.1.5
	 * @return
	 */
	private static String generateQueryReqSN() {
		return QUERY_REQ_SN_PRE + Long.toString(Calendar.getInstance().getTime().getTime());
	}

	/**
	 * 构建查询代付的响应结果
	 *
	 * @author wujiande
	 * @date 2018-05-11 17:22:08
	 * @since v2.1.5
	 * @param req
	 * @param responseStr
	 * @param configExt
	 * @return
	 * @throws Exception
	 */
	private QueryPayoutOrderYYContent transformQueryPayOutOrderContent(QueryPayoutOrderYYContent content, QueryPayoutOrderYYParams req,
			String responseStr, AllInPayConfigExt configExt) throws Exception {
		final String op = "AllInPayFacade.transformQueryPayOutOrderContent";

		if (StringUtils.isBlank(responseStr)) {
			// 如果请求响应参数为空则未知
			logger.error(Log.op(op).msg("【通联】【查询代付】请求响应报文为空，需要人工介入").kv("payoutOrderId", req.getPayoutOrderId()).toString());
			content.setResultCode(PayExceptionCode.WARN_UNKNOWN.getCode());
			content.setResultMsg(PayExceptionCode.WARN_UNKNOWN.getDesc());
			return content;
		}
		// step3.解析通联返回参数
		boolean sign = AllInPayUtil.verfiySign(req.getMerchantCode(), responseStr, configExt.getPublicKeyPath());
		if (!sign) {
			// 响应报文验签不通过
			logger.error(Log.op(op).msg("【通联】【查询代付】请求响应报文验签不通过，订单查询失败，需要人工介入").kv("payoutOrderId", req.getPayoutOrderId()).kv("响应报文", responseStr)
					.toString());

			content.setResultCode(PayExceptionCode.WARN_UNKNOWN.getCode());
			content.setResultMsg("第三方支付响应报文验签异常，未知状态");
			return content;
		}
		// step4.转换通联返回参数为支付返回参数
		AllInPayRspXML fromXMLForXStream = XmlUtil.fromXMLForXStream(responseStr, AllInPayRspXML.class, QueryRspXML.class);
		Pair<Integer, String> pairRspCode = transformRspCodeForQuery(fromXMLForXStream, req);

		content.setResultCode(pairRspCode.first());
		content.setResultMsg(pairRspCode.second());
		return content;
	}

	/**
	 * 转换查询代付通联响应码
	 *
	 * @author wujiande
	 * @date 2018-05-17 12:54:29
	 * @since v2.1.5
	 * @param fromXMLForXStream
	 * @param req
	 * @return
	 */
	private Pair<Integer, String> transformRspCodeForQuery(AllInPayRspXML fromXMLForXStream, QueryPayoutOrderYYParams req) {
		final String op = "AllInPayFacade.transformRspCodeForQuery";
		if (fromXMLForXStream == null || fromXMLForXStream.getInfo() == null) {
			logger.error(Log.op(op).msg("转换通联响应码，响应参数实体为空，响应业务状态码为未知状态，需要人工介入").kv("AllInPayRspXML", fromXMLForXStream).toString());
			return Pair.of(PayExceptionCode.WARN_UNKNOWN.getCode(), "未知状态，响应信息为空");
		}

		String reqCode = fromXMLForXStream.getInfo().getReqCode();
		String infoErrMsg = fromXMLForXStream.getInfo().getErrMsg();

		if (AllInPayRspCodeEnum.isReqMsgError(reqCode)) {
			// 报文解析异常
			infoErrMsg = StringUtils.isBlank(infoErrMsg) ? PayExceptionCode.WARN_UNKNOWN.getDesc() : infoErrMsg;
			logger.warn(Log.op(op).msg("通联 | 代付 | 查询 | 响应报文格式非法，响应业务状态码为未知状态，需要人工介入").kv("AllInPayRspXML", fromXMLForXStream).toString());
			return Pair.of(PayExceptionCode.WARN_UNKNOWN.getCode(), infoErrMsg);
		}

		if (AllInPayRspCodeEnum.REVERSE_ORDER_NOT_FOUND.isValue(reqCode)) {
			// 如果报文头响应码是1002，则默认为失败，并且打印一个异常日志，通过运维监控
			logger.error(Log.op(op).msg("通联 | 代付 | 查询 | 报文头响应码1002-冲正无此交易，默认判定为失败，需要人工介入，重新确认结果").kv("AllInPayRspXML", fromXMLForXStream).toString());
			return Pair.of(PayExceptionCode.ERROR_PAYOUT_FAIL.getCode(), infoErrMsg);
		}

		return transformRspCode(fromXMLForXStream, req.getPayoutOrderId());
	}

	@Override
	public void getRefundNotifyResult(HttpServletRequest request, PayoutRefundDataBinder binder) throws Exception {
		final String op = "AllInPayFacade.getRefundNotifyResult";

		logger.info(Log.op(op).msg("通联 | 单笔代付 | 退票异步通知请求参数").kv("req", WebUtils.getParametersStartingWith(request,"")).toString());
		
		// 校验基本参数
		if (StringUtils.isBlank(request.getParameter("BATCHID"))) {
			logger.warn(Log.op(op).msg("通联 | 单笔代付 | 退票 请求批次号batchid为空").toString());
			binder.setException(PayExceptionCode.ERROR_ILL_PARAMETER.exp());
			return;
		}

		if (StringUtils.isBlank(request.getParameter("AMOUNT")) || !NumberUtils.isDigits(request.getParameter("AMOUNT"))) {
			logger.warn(Log.op(op).msg("通联 | 单笔代付 | 退票 请求参数AMOUNT非法").kv("AMOUNT", request.getParameter("AMOUNT"))
					.kv("BATCHID", request.getParameter("BATCHID")).toString());
			binder.setException(PayExceptionCode.ERROR_ILL_PARAMETER.exp());
			return;
		}

		if (StringUtils.isBlank(request.getParameter("POUNDAGE")) || !NumberUtils.isDigits(request.getParameter("POUNDAGE"))) {
			logger.warn(Log.op(op).msg("通联 | 单笔代付 | 退票 请求参数POUNDAGE非法").kv("POUNDAGE", request.getParameter("POUNDAGE"))
					.kv("BATCHID", request.getParameter("BATCHID")).toString());
			binder.setException(PayExceptionCode.ERROR_ILL_PARAMETER.exp());
			return;
		}

		PayoutRefundReq req = new PayoutRefundReq();
		req.setRetCode(request.getParameter("RETCODE"));
		req.setRetMsg(request.getParameter("RETMSG"));
		String accountNo = request.getParameter("ACCOUNT_NO");
		req.setAccountNo(StringUtils.isBlank(accountNo) ? "" : accountNo);
		req.setMobile(request.getParameter("MOBILE"));
		req.setAmount(Long.valueOf(request.getParameter("AMOUNT")));
		req.setSettDay(request.getParameter("SETTDAY"));
		req.setFinTime(request.getParameter("FINTIME"));
		req.setSubmitTime(request.getParameter("SUBMITTIME"));
		req.setBatchId(request.getParameter("BATCHID"));
		req.setSn(request.getParameter("SN"));
		req.setPoundage(Long.valueOf(request.getParameter("POUNDAGE")));
		req.setUserCode(request.getParameter("USERCODE"));
		req.setSign(request.getParameter("SIGN"));


		// 账号|手机号|金额|交易批次号|流水号|手续费
		String destSign = req.getAccountNo().concat("|").concat(req.getMobile()).concat("|").concat(req.getAmount() + "").concat("|")
				.concat(req.getBatchId()).concat("|").concat(req.getSn()).concat("|").concat(req.getPoundage() + "");

		// step1.转换为查询通联代付订单的请求参数
		AllInPayConfigExt configExt = getConfigExt(binder.getMerchantCode(), PayTypeEnum.PAY_OUT);

		boolean sign = AllInPayUtil.verfiySignWithAlias(binder.getMerchantCode(), destSign, req.getSign(), configExt.getPublicKeyPath());
		if (!sign) {
			// 响应报文验签不通过
			logger.error(Log.op(op).msg("通联 | 单笔代付 | 退票验签不通过，订单不修改，需要人工介入").kv("payoutOrderId", req.getSn()).kv("响应报文", req).toString());

			// 抛出异常签名失败
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		// 通联代付退票批次流水号表示支付模块传输过去的流水号
		binder.setBusiId(req.getBatchId());
		// 设置响应成功
		binder.setRspMsg("SUCCESS");
	}

}
